package com.hm.myapplication

import android.content.Context
import android.content.res.Resources
import android.graphics.Canvas
import android.util.AttributeSet
import android.util.TypedValue
import android.view.View
import android.view.ViewGroup
import kotlin.math.max

class MyFlowLayout : ViewGroup {

    private val mHorizontalSpacing = dp2px(16) //每个item横向间距

    private val mVerticalSpacing = dp2px(8) //每个item横向间距


    private val allLines = ArrayList<ArrayList<View>>()  // 记录所有的行，一行一行的存储，用于layout
    private val lineHeights = ArrayList<Int>()  // 记录每一行的行高，用于layout

    constructor(context: Context?) : super(context)

    constructor(context: Context?, attributeSet: AttributeSet?) : super(context, attributeSet)

    constructor(context: Context?, attributeSet: AttributeSet?, defStyleAttr: Int) : super(
        context,
        attributeSet,
        defStyleAttr
    )


    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        //清空之前记录的数据
        allLines.clear()
        lineHeights.clear()
        //获取子view个数，以及外部距离
        val childCount = childCount
        val paddingTop = paddingTop
        val paddingBottom = paddingBottom
        val paddingLeft = paddingLeft
        val paddingRight = paddingRight


        //解析父布局给我的宽度和高度
        val sufWidthSize = MeasureSpec.getSize(widthMeasureSpec)
        val sufheightSize = MeasureSpec.getSize(heightMeasureSpec)

        var lineViews = ArrayList<View>() //保存一行中的所有的view

        var lineWidthUsed = 0 //记录这行已经使用了多宽的size

        var lineHeight = 0 // 一行的行高


        var parentNeededWidth = 0 // measure过程中，子View要求的父ViewGroup的宽

        var parentNeededHeight = 0 // measure过程中，子View要求的父ViewGroup的高



        for (i in 0 until childCount)  {
            val childAt = getChildAt(i)

            val layoutParams = childAt.layoutParams

            if (childAt.visibility != GONE) {
                //将layoutParams转变成为 measureSpec
                val childWidthMeasureSpec = getChildMeasureSpec(
                    widthMeasureSpec,
                    paddingLeft + paddingRight,
                    layoutParams.width
                )
                val childHeightMeasureSpec = getChildMeasureSpec(
                    heightMeasureSpec,
                    paddingTop + paddingBottom,
                    layoutParams.height
                )


                childAt.measure(childWidthMeasureSpec, childHeightMeasureSpec)

                // 获取子view的度量宽高
                val measuredHeight = childAt.measuredHeight
                val measuredWidth = childAt.measuredWidth


                //如果需要换行

                if((lineWidthUsed + measuredWidth + mHorizontalSpacing) > sufWidthSize){

                    //一旦换行，我们就可以判断当前行需要的宽和高了，所以此时要记录下来

                    allLines.add(lineViews) //记录下每一行的view
                    lineHeights.add(lineHeight) //记录这一行的高度

                    parentNeededHeight = parentNeededHeight + lineHeight + mVerticalSpacing
                    parentNeededWidth = max(parentNeededWidth,lineWidthUsed+mHorizontalSpacing)

                    //换行需要清空数据
                    lineViews = ArrayList<View>()//清空一行的数据用于新一行开始
                    lineHeight = 0 //新一行高度重新记录
                    lineWidthUsed = 0 //宽度重新记录

                }



                // view 是分行layout的，所以要记录每一行有哪些view，这样可以方便layout布局
                lineViews.add(childAt)
                //每行都会有自己的宽和高
                lineWidthUsed = lineWidthUsed + measuredWidth + mHorizontalSpacing
                lineHeight  = max(lineHeight,measuredHeight)

                //处理最后一行数据
                if (i ==  childCount -1){
                    allLines.add(lineViews) //记录下每一行的view
                    lineHeights.add(lineHeight) //记录这一行的高度

                    parentNeededHeight = parentNeededHeight + lineHeight + mVerticalSpacing //记录整个父布局view需要的高度
                    parentNeededWidth = max(parentNeededWidth,lineWidthUsed+mHorizontalSpacing)//记录整个父布局需要的宽度

                }

            }
        }

        //再度量自己,保存
        //根据子View的度量结果，来重新度量自己ViewGroup
        // 作为一个ViewGroup，它自己也是一个View,它的大小也需要根据它的父亲给它提供的宽高来度量
        val widthmode = MeasureSpec.getMode(widthMeasureSpec)
        val heightmode = MeasureSpec.getMode(heightMeasureSpec)

        val realWidth = if (widthmode == MeasureSpec.EXACTLY) sufWidthSize else parentNeededWidth
        val realHeight = if (heightmode == MeasureSpec.EXACTLY) sufheightSize else parentNeededHeight

        setMeasuredDimension(realWidth,realHeight)//将测量后的大小设置到父布局中
    }

    override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {

        //布局先获取到所有view循环便利
        val vcont = allLines.size


        var top = paddingTop//获取最初顶部位置
        var left = paddingLeft

        for (i in 0 until vcont) {

            val itemview = allLines[i]   //拿到每一行的view

            val lineHeight = lineHeights[i]
            itemview.forEach {

                var reight = left + it.measuredWidth
                var bottom = top + it.measuredHeight
                it.layout(left,top,reight,bottom)

                left = reight + mHorizontalSpacing
            }
            top = top +  lineHeight + mVerticalSpacing
            left = paddingLeft
        }




    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)


    }

    //    @Override
    //    protected void onDraw(Canvas canvas) {
    //        super.onDraw(canvas);
    //    }
    fun dp2px(dp: Int): Int = TypedValue.applyDimension(
        TypedValue.COMPLEX_UNIT_DIP,
        dp.toFloat(),
        Resources.getSystem().displayMetrics
    ).toInt()

}